package com.zzyl.nursing.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.core.page.TableDataInfo;
import com.zzyl.nursing.domain.Reservation;
import com.zzyl.nursing.mapper.ReservationMapper;
import com.zzyl.nursing.service.IReservationService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ReservationServiceImpl extends ServiceImpl<ReservationMapper, Reservation> implements IReservationService {

    private static final int MAX_RESERVATIONS_PER_TIME = 6;

    // 工具方法：LocalDateTime 转 Date（适配实体类的Date字段）
    private Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    // 工具方法：LocalDate 转 Date（用于查询）
    private Date localDateToDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    @Override
    public Integer getCancelledCountToday(Long userId) {
        // 当天开始时间（LocalDateTime -> Date）
        LocalDateTime todayStartLdt = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        Date todayStart = localDateTimeToDate(todayStartLdt);
        // 当天结束时间（LocalDateTime -> Date）
        LocalDateTime todayEndLdt = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        Date todayEnd = localDateTimeToDate(todayEndLdt);
        return baseMapper.selectCancelledCountToday(userId, todayStart, todayEnd);
    }

    @Override
    public List<Reservation> getRemainingCountByTime(Date date) {
        // 提取日期部分（确保查询当天所有时间段）
        LocalDate localDate = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        Date startOfDay = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date endOfDay = Date.from(localDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());

        // 查询当天已预约且未取消的记录，按时间段分组统计
        List<Reservation> bookedList = baseMapper.selectCountByTimeRange(startOfDay, endOfDay);

        // 计算剩余次数（假设每个时间段最多约 6 次）
        return bookedList.stream().map(item -> {
            item.setCount(6 - item.getCount());
            return item;
        }).collect(Collectors.toList());
    }

    @Transactional
    @Override
    public boolean createReservation(Reservation reservation, Long userId) {
        // 校验1：当天取消次数≤3次
        Integer cancelCount = getCancelledCountToday(userId);
        if (cancelCount >= 3) {
            throw new RuntimeException("当天取消预约次数已达3次，无法继续预约");
        }

        // 校验2：时间段剩余次数>0
        // 假设 reserveDate 是 LocalDate 类型（例如从 reservation.getTime() 转换得到）
        LocalDate reserveDate = reservation.getTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate(); // 从Date转LocalDate（获取日期部分）

        // 关键：调用 getRemainingCountByTime 前，将 LocalDate 转为 Date
        Date queryDate = localDateToDate(reserveDate);
        List<Reservation> remainingList = getRemainingCountByTime(queryDate); // 现在参数类型匹配

        Map<String, Integer> timeCountMap = new HashMap<>();
        remainingList.forEach(item -> timeCountMap.put(item.getTime().toString(), item.getCount()));
        Integer remaining = timeCountMap.getOrDefault(reservation.getTime().toString(), MAX_RESERVATIONS_PER_TIME);
        if (remaining <= 0) {
            throw new RuntimeException("该时间段已约满，请选择其他时间");
        }

        // 校验3：手机号+时间唯一（排除已取消的预约）
        List<Reservation> existing = list(new QueryWrapper<Reservation>()
                .eq("mobile", reservation.getMobile())
                .eq("time", reservation.getTime())
                .ne("status", 2));
        if (!existing.isEmpty()) {
            throw new RuntimeException("该手机号在该时间段已预约，请选择其他时间");
        }

        // 设置创建时间（LocalDateTime -> Date）
        reservation.setCreateBy(String.valueOf(userId)); // Long -> String
        reservation.setCreateTime(localDateTimeToDate(LocalDateTime.now())); // 核心修改
        reservation.setStatus(0); // 初始状态：待报道
        return save(reservation);
    }

    @Override
    public TableDataInfo getUserReservationPage(Integer pageNum, Integer pageSize, Long userId, Reservation reservation) {
        Page<Reservation> page = new Page<>(pageNum, pageSize);
        IPage<Reservation> iPage = baseMapper.selectUserReservationPage(page, userId, reservation);

        TableDataInfo tableData = new TableDataInfo();
        tableData.setTotal(iPage.getTotal()); // 总条数
        tableData.setRows(iPage.getRecords()); // 列表数据（替换原records）
        return tableData;
    }

    @Transactional
    @Override
    public boolean cancelReservation(Long id, Long userId) {
        Reservation reservation = getById(id);
        if (reservation == null) {
            throw new RuntimeException("预约记录不存在");
        }
        // 关键修改：将userId转为String，与createBy（String类型）匹配
        String userIdStr = String.valueOf(userId);
        // 校验：创建人必须匹配 + 状态必须是“待报道（0）”
        if (!reservation.getCreateBy().equals(userIdStr) || reservation.getStatus() != 0) {
            throw new RuntimeException("无权限取消该预约");
        }
        // 更新状态和时间
        reservation.setStatus(2); // 2=已取消
        reservation.setUpdateBy(userIdStr);
        reservation.setUpdateTime(new Date()); // 直接用当前时间，简化转换
        return updateById(reservation);
    }

    @Transactional
    public void handleExpiredReservations() {
        Date now = new Date();
        // 查询：状态为“待报道”且预约时间已过的记录
        List<Reservation> expiredList = list(new QueryWrapper<Reservation>()
                .eq("status", 0) // 0=待报道
                .lt("time", now)); // 预约时间 < 当前时间

        if (expiredList.isEmpty()) {
            return;
        }
        // 批量更新状态为“过期”（3），并设置更新时间
        expiredList.forEach(item -> {
            item.setStatus(3);
            item.setUpdateTime(now);
            item.setUpdateBy("system"); // 标记为系统自动更新
        });
        updateBatchById(expiredList);
    }
}